package com.changgou.lock;

import com.changgou.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;


import java.security.SecureRandom;
import java.util.concurrent.TimeUnit;


@Slf4j
public class RedisLock {

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private RedisTemplate redisTemplate;

    public static  final  String REDIS_LOCK = "RedisLock:";

    // 默认设置 10s 锁超时时间
    private static  final  long DEFAULT_WAIT_LOCK_TIMEOUT = 10;

    // 默认设置 10s 锁的有效时间
    private  static  final  long DEFAULT_EXPIRE = 10;

    public boolean lock(String key){
        log.info("加锁key={}",key);
       return lock(key,DEFAULT_WAIT_LOCK_TIMEOUT,TimeUnit.SECONDS);
    }


    /**
    *@Description   加锁
    *@Param
     * @param key
     * @param timeout
     * @param seconds
    *@Return boolean
    *@Author feilx
    */
    public boolean lock(String key, long timeout, TimeUnit seconds){
      String lockKey = generateLockKey(key);

        // 获取超时时间 以纳秒为单位
        long nanosWaitForLock = seconds.toNanos(timeout);
        // 开始时间
        long start = System.nanoTime();
        RedisConnection connection = null;
       try{
           connection = redisTemplate.getConnectionFactory().getConnection();
           do{
               if(connection.setNX(lockKey.getBytes(),new byte[0])){
                   // 暂设置10s过期,防止异常中断锁为释放
                   redisTemplate.expire(lockKey,DEFAULT_EXPIRE,TimeUnit.SECONDS);
                   if(log.isDebugEnabled()){
                       log.debug("add RedisLoc[{}].{}",key,Thread.currentThread());
                   }
                   return  true;
               }
               // 加随机时间防止活锁
               TimeUnit.MILLISECONDS.sleep(10001 + new SecureRandom().nextInt(100));
           }while ((System.nanoTime() - start) < nanosWaitForLock);
       }catch (Exception e){
          log.error("{}",e.getMessage(),e);
          // 出现异常解锁
          unlock(key);
       }finally {
           // 关闭连接
           if(null != connection){
               connection.close();
           }
       }
      return  false;
    }

    // 解锁
    public void unlock(String key) {
        log.info("释放锁key={}",key);
        RedisConnection connection = null;
        try{
            String lockKey = generateLockKey(key);
            connection = redisTemplate.getConnectionFactory().getConnection();
            connection.del(key.getBytes());
        }catch (Exception e){
           log.error("{}",e.getMessage(),e);
        }finally {
            // 关闭连接
            if(null != connection){
                connection.close();
            }
        }
    }

    // 组装锁
    private String generateLockKey(String key) {
        return String.format(REDIS_LOCK+"%s",key);
    }

    public boolean lockCron(String key, long expire, TimeUnit seconds){
        String lockKey = generateLockKey(key);

        // 获取超时时间 以纳秒为单位
        long nanosWaitForLock = seconds.toNanos(01);
        // 开始时间
        long start = System.nanoTime();
        RedisConnection connection = null;
        try{
            connection = redisTemplate.getConnectionFactory().getConnection();
            do{
                if(connection.setNX(lockKey.getBytes(),new byte[0])){
                    // 暂设置10s过期,防止异常中断锁为释放
                    redisTemplate.expire(lockKey,DEFAULT_EXPIRE,TimeUnit.SECONDS);
                    if(log.isDebugEnabled()){
                        log.debug("add RedisLoc[{}].{}",key,Thread.currentThread());
                    }
                    return  true;
                }
                // 加随机时间防止活锁
                TimeUnit.MILLISECONDS.sleep(10001 + new SecureRandom().nextInt(100));
            }while ((System.nanoTime() - start) < nanosWaitForLock);
        }catch (Exception e){
            log.error("{}",e.getMessage(),e);
            // 出现异常解锁
            unlock(key);
        }finally {
            // 关闭连接
            if(null != connection){
                connection.close();
            }
        }
        return  false;
    }


}
